home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / stdio / RCS / vfscanf.c,v < prev    next >
Text File  |  1992-01-21  |  13KB  |  643 lines

  1. head     1.6;
  2. branch   ;
  3. access   ;
  4. symbols  sprited:1.5.1;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.6
  10. date     92.01.21.16.27.07;  author rab;  state Exp;
  11. branches ;
  12. next     1.5;
  13.  
  14. 1.5
  15. date     90.09.11.14.27.16;  author kupfer;  state Exp;
  16. branches 1.5.1.1;
  17. next     1.4;
  18.  
  19. 1.4
  20. date     89.09.15.12.08.48;  author douglis;  state Exp;
  21. branches ;
  22. next     1.3;
  23.  
  24. 1.3
  25. date     88.07.25.13.12.45;  author ouster;  state Exp;
  26. branches ;
  27. next     1.2;
  28.  
  29. 1.2
  30. date     88.07.21.09.36.33;  author ouster;  state Exp;
  31. branches ;
  32. next     1.1;
  33.  
  34. 1.1
  35. date     88.06.10.16.23.37;  author ouster;  state Exp;
  36. branches ;
  37. next     ;
  38.  
  39. 1.5.1.1
  40. date     91.12.02.20.05.34;  author kupfer;  state Exp;
  41. branches ;
  42. next     ;
  43.  
  44.  
  45. desc
  46. @@
  47.  
  48.  
  49. 1.6
  50. log
  51. @Fixed handling of %[^] pattern where no chars
  52. are accepted (ie: first streamChar matches a
  53. pattern char).  Must not update assignedFields
  54. and must abort outer 'for' loop.
  55. @
  56. text
  57. @/* 
  58.  * vfscanf.c --
  59.  *
  60.  *    Source code for the "vfscanf" library procedure.
  61.  *
  62.  * Copyright 1988 Regents of the University of California
  63.  * Permission to use, copy, modify, and distribute this
  64.  * software and its documentation for any purpose and without
  65.  * fee is hereby granted, provided that the above copyright
  66.  * notice appear in all copies.  The University of California
  67.  * makes no representations about the suitability of this
  68.  * software for any purpose.  It is provided "as is" without
  69.  * express or implied warranty.
  70.  */
  71.  
  72. #ifndef lint
  73. static char rcsid[] = "$Header: /sprite/src/lib/c/stdio/RCS/vfscanf.c,v 1.5 90/09/11 14:27:16 kupfer Exp Locker: rab $ SPRITE (Berkeley)";
  74. #endif not lint
  75.  
  76. #include <sprite.h>
  77. #include <stdio.h>
  78. #include <ctype.h>
  79. #include <stdlib.h>
  80. #include <varargs.h>
  81.  
  82. #ifndef TRUE
  83. #define TRUE 1
  84. #endif
  85. #ifndef FALSE
  86. #define FALSE 0
  87. #endif
  88.  
  89. /*
  90.  * Maximum number of bytes in allowable ASCII representation of a
  91.  * floating-point number:
  92.  */
  93.  
  94. #define MAX_FLOAT_SIZE 350
  95. /*
  96.  *----------------------------------------------------------------------
  97.  *
  98.  * vfscanf --
  99.  *
  100.  *    This utility routine does all of the real work of scanning
  101.  *    fields under control of a format string.  It is called by
  102.  *    scanf, fscanf, and sscanf.
  103.  *
  104.  * Results:
  105.  *    Values addressed by elements of args are modified to hold
  106.  *    values scanned from stream.  The return value is a count of
  107.  *    the number of fields successfully scanned from stream, or
  108.  *    EOF if no characters could be input from stream.
  109.  *
  110.  * Side effects:
  111.  *    Information is input from stream.
  112.  *
  113.  *----------------------------------------------------------------------
  114.  */
  115.  
  116. int
  117. vfscanf(stream, format, args)
  118.     register FILE *stream;    /* Where to read characters for parsing. */
  119.     register char *format;    /* Contains literal text and format control
  120.                  * sequences indicating how args are to be
  121.                  * scanned.  See the man page for details. */
  122.     va_list args;        /* Addresses of a variable number of arguments
  123.                  * to be modified. */
  124. {
  125.     int suppress;        /* TRUE means scan value but don't actual
  126.                  * modify an element of args. */
  127.     int storeShort;        /* TRUE means store a short value. */
  128.     int storeLong;        /* TRUE means store a long value. */
  129.     int width;            /* Field width. */
  130.     register char formatChar;     /* Current character from format string.
  131.                  * Eventually it ends up holding the format
  132.                  * type (e.g. 'd' for decimal). */
  133.     register int streamChar;    /* Next character from stream. */
  134.     int assignedFields;        /* Counts number of successfully-assigned
  135.                  * fields. */
  136.     int base;            /* Gives base for numbers:  0 means float,
  137.                  * -1 means not a number.
  138.                  */
  139.     int sign;            /* TRUE means negative sign. */
  140.     char buf[MAX_FLOAT_SIZE+1];
  141.                 /* Place to accumulate floating-point
  142.                  * number for processing. */
  143.     register char *ptr = (char *) NIL;
  144.     char *savedPtr, *end, *firstPtr;
  145.  
  146.     assignedFields = 0;
  147.     streamChar = getc(stream);
  148.     if (streamChar == EOF) {
  149.     return(EOF);
  150.     }
  151.  
  152.     /*
  153.      * The main loop is to scan through the characters in format.
  154.      * Anything but a '%' must match the next character from stream.
  155.      * A '%' signals the start of a format field;  the formatting
  156.      * information is parsed, the next value is scanned from the stream
  157.      * and placed in memory, and the loop goes on.
  158.      */
  159.  
  160.     for (formatChar = *format; (formatChar != 0) && (streamChar != EOF);
  161.         format++, formatChar = *format) {
  162.     
  163.     /*
  164.      * A white-space format character matches any number of
  165.      * white-space characters from the stream.
  166.      */
  167.  
  168.     if (isspace(formatChar)) {
  169.         while (isspace(streamChar)) {
  170.         streamChar = getc(stream);
  171.         }
  172.         continue;
  173.     }
  174.  
  175.     /*
  176.      * Any character but % must be matched exactly by the stream.
  177.      */
  178.  
  179.     if (formatChar != '%') {
  180.         if (streamChar != formatChar) {
  181.         break;
  182.         }
  183.         streamChar = getc(stream);
  184.         continue;
  185.     }
  186.  
  187.     /*
  188.      * Parse off the format control fields.
  189.      */
  190.  
  191.     suppress = FALSE;
  192.     storeLong = FALSE;
  193.     storeShort = FALSE;
  194.     width = -1;
  195.     format++;  
  196.     formatChar = *format;
  197.     if (formatChar == '*') {
  198.         suppress = TRUE;
  199.         format++; 
  200.         formatChar = *format;
  201.     }
  202.     if (isdigit(formatChar)) {
  203.         width = strtoul(format, &end, 10);
  204.         format = end;
  205.         formatChar = *format;
  206.     }
  207.     if (formatChar == 'l') {
  208.         storeLong = TRUE;
  209.         format++; 
  210.         formatChar = *format;
  211.     }
  212.     if (formatChar == 'h') {
  213.         storeShort = TRUE;
  214.         format++; 
  215.         formatChar = *format;
  216.     }
  217.  
  218.     /*
  219.      * Skip any leading blanks in the input (except for 'c' format).
  220.      * Also, default the width to infinity, except for 'c' format.
  221.      */
  222.     
  223.     if ((formatChar != 'c') && (formatChar != '[')) {
  224.         while (isspace(streamChar)) {
  225.         streamChar = getc(stream);
  226.         }
  227.     }
  228.     if ((width <= 0) && (formatChar != 'c')) {
  229.         width = 1000000;
  230.     }
  231.  
  232.     /*
  233.      * Check for EOF again after parsing away the white space.
  234.      */
  235.     if (streamChar == EOF) {
  236.         break;
  237.     }
  238.     
  239.     /*
  240.      * Process the conversion character.  For numbers, this just means
  241.      * turning it into a "base" number that indicates how to read in
  242.      * a number.
  243.      */
  244.     
  245.     base = -1;
  246.     switch (formatChar) {
  247.  
  248.         case '%':
  249.         if (streamChar != '%') {
  250.             goto done;
  251.         }
  252.         streamChar = getc(stream);
  253.         break;
  254.         
  255.         case 'D':
  256.         storeShort = FALSE;
  257.         case 'd':
  258.         base = 10;
  259.         break;
  260.         
  261.         case 'O':
  262.         storeShort = FALSE;
  263.         case 'o':
  264.         base = 8;
  265.         break;
  266.         
  267.         case 'X':
  268.         storeShort = FALSE;
  269.         case 'x':
  270.         base = 16;
  271.         break;
  272.         
  273.         case 'E':
  274.         case 'F':
  275.         storeLong = TRUE;
  276.         case 'e':
  277.         case 'f':
  278.         base = 0;
  279.         break;
  280.  
  281.         /*
  282.          * Characters and strings are handled in exactly the same way,
  283.          * except that for characters the default width is 1 and spaces
  284.          * are not considered terminators.
  285.          */
  286.  
  287.         case 'c':
  288.         if (width <= 0) {
  289.             width = 1;
  290.         }
  291.         case 's':
  292.         if (suppress) {
  293.             while ((width > 0) && (streamChar != EOF)) {
  294.             if (isspace(streamChar) && (formatChar == 's')) {
  295.                 break;
  296.             }
  297.             streamChar = getc(stream);
  298.             width--;
  299.             }
  300.         } else {
  301.             ptr = va_arg(args, char *);
  302.             while ((width > 0) && (streamChar != EOF)) {
  303.             if (isspace(streamChar) && (formatChar == 's')) {
  304.                 break;
  305.             }
  306.             *ptr = streamChar;
  307.             ptr++;
  308.             streamChar = getc(stream);
  309.             width--;
  310.             }
  311.             if (formatChar == 's') {
  312.             *ptr = 0;
  313.             }
  314.             assignedFields++;
  315.         }
  316.         break;
  317.         
  318.         case '[':
  319.         format++; formatChar = *format;
  320.         if (formatChar == '^') {
  321.             format++;
  322.         }
  323.         if (!suppress) {
  324.             firstPtr = ptr = va_arg(args, char *);
  325.         }
  326.         savedPtr = format;
  327.         while ((width > 0) && (streamChar != EOF)) {
  328.             format = savedPtr;
  329.             while (TRUE) {
  330.             if (*format == streamChar) {
  331.                 if (formatChar == '^') {
  332.                 goto stringEnd;
  333.                 } else {
  334.                 break;
  335.                 }
  336.             }
  337.             if ((*format == ']') || (*format == 0)) {
  338.                 if (formatChar == '^') {
  339.                 break;
  340.                 } else {
  341.                 goto stringEnd;
  342.                 }
  343.             }
  344.             format++;
  345.             }
  346.             if (!suppress) {
  347.             *ptr = streamChar;
  348.             ptr++;
  349.             }
  350.             streamChar = getc(stream);
  351.             width--;
  352.         }
  353.         stringEnd:
  354.         if (ptr == firstPtr) {
  355.             goto done;
  356.         }
  357.         while ((*format != ']') && (*format != 0)) {
  358.             format++;
  359.         }
  360.         formatChar = *format;
  361.         if (!suppress) {
  362.             *ptr = 0;
  363.             assignedFields++;
  364.         }
  365.         break;
  366.  
  367.         /*
  368.          * Don't ask why, but for compatibility with UNIX, a null
  369.          * conversion character must always return EOF, and any
  370.          * other conversion character must be treated as decimal.
  371.          */
  372.         
  373.         case 0:
  374.         ungetc(streamChar, stream);
  375.         return(EOF);
  376.         
  377.         default:
  378.         base = 10;
  379.         break;
  380.     }
  381.  
  382.     /*
  383.      * If the field wasn't a number, then everything was handled
  384.      * in the switch statement above.  Otherwise, we still have
  385.      * to read in a number.  This gets handled differently for
  386.      * integers and floating-point numbers.
  387.      */
  388.     
  389.     if (base < 0) {
  390.         continue;
  391.     }
  392.  
  393.     if (streamChar == '-') {
  394.         sign = TRUE;
  395.         width -= 1;
  396.         streamChar = getc(stream);
  397.     } else {
  398.         sign = FALSE;
  399.         if (streamChar == '+') {
  400.         width -= 1;
  401.         streamChar = getc(stream);
  402.         }
  403.     }
  404.  
  405.     /*
  406.      * If we're supposed to be parsing a floating-point number, read
  407.      * the digits into a temporary buffer and use the conversion library
  408.      * routine to convert them.
  409.      */
  410.     
  411. #define COPYCHAR \
  412.     *ptr = streamChar; ptr++; width--; streamChar = getc(stream);
  413.  
  414.     if (base == 0) {
  415.         if (width > MAX_FLOAT_SIZE) {
  416.         width = MAX_FLOAT_SIZE;
  417.         }
  418.         ptr = buf;
  419.         while ((width > 0) && isdigit(streamChar)) {
  420.         COPYCHAR;
  421.         }
  422.         if ((width > 0) && (streamChar == '.')) {
  423.         COPYCHAR;
  424.         }
  425.         while ((width > 0) && isdigit(streamChar)) {
  426.         COPYCHAR;
  427.         }
  428.         if ((width > 0) && ((streamChar == 'e') || (streamChar == 'E'))) {
  429.         COPYCHAR;
  430.         if ((width > 0) &&
  431.             ((streamChar == '+') || (streamChar == '-'))) {
  432.             COPYCHAR;
  433.         }
  434.         while ((width > 0) && isdigit(streamChar)) {
  435.             COPYCHAR;
  436.         }
  437.         }
  438.         *ptr = 0;
  439.  
  440.         if (ptr == buf) {        /* Not a valid number. */
  441.         goto done;
  442.         }
  443.  
  444.         if (!suppress) {
  445.         double d;
  446.         d = atof(buf);
  447.         if (sign) {
  448.             d = -d;
  449.         }
  450.         if (storeLong) {
  451.             *(va_arg(args, double *)) = d;
  452.         } else {
  453.             *(va_arg(args, float *)) = d;
  454.         }
  455.         assignedFields++;
  456.         }
  457.     } else {
  458.         /*
  459.          * This is an integer.  Use special-purpose code for the
  460.          * three supported bases in order to make it run fast.
  461.          */
  462.  
  463.         int i;
  464.         int anyDigits;
  465.  
  466.         i = 0;
  467.         anyDigits = FALSE;
  468.         if (base == 10) {
  469.         while ((width > 0) && isdigit(streamChar)) {
  470.             i = (i * 10) + (streamChar - '0');
  471.             streamChar = getc(stream);
  472.             anyDigits = TRUE;
  473.             width -= 1;
  474.         }
  475.         } else if (base == 8) {
  476.         while ((width > 0) && (streamChar >= '0')
  477.             && (streamChar <= '7')) {
  478.             i = (i << 3) + (streamChar - '0');
  479.             streamChar = getc(stream);
  480.             anyDigits = TRUE;
  481.             width -= 1;
  482.         }
  483.         } else {
  484.         while (width > 0) {
  485.             if (isdigit(streamChar)) {
  486.             i = (i << 4) + (streamChar - '0');
  487.             } else if ((streamChar >= 'a') && (streamChar <= 'f')) {
  488.             i = (i << 4) + (streamChar + 10 - 'a');
  489.             } else if ((streamChar >= 'A') && (streamChar <= 'F')) {
  490.             i = (i << 4) + (streamChar + 10 - 'A');
  491.             } else {
  492.             break;
  493.             }
  494.             streamChar = getc(stream);
  495.             anyDigits = TRUE;
  496.             width--;
  497.         }
  498.         }
  499.         if (!anyDigits) {
  500.         goto done;
  501.         }
  502.         if (sign) {
  503.         i = -i;
  504.         }
  505.         if (!suppress) {
  506.         if (storeShort) {
  507.             *(va_arg(args, short *)) = i;
  508.         } else {
  509.             *(va_arg(args, int *)) = i;
  510.         }
  511.         assignedFields++;
  512.         }
  513.     }
  514.     }
  515.  
  516.     done:
  517.     ungetc(streamChar, stream);
  518.     if ((streamChar == EOF) && (assignedFields == 0)) {
  519.     return(EOF);
  520.     }
  521.     return(assignedFields);
  522. }
  523. @
  524.  
  525.  
  526. 1.5
  527. log
  528. @Use function prototypes. Lint.
  529. @
  530. text
  531. @d17 1
  532. a17 1
  533. static char rcsid[] = "$Header: /sprite/src/lib/c/stdio/RCS/vfscanf.c,v 1.4 89/09/15 12:08:48 douglis Exp Locker: kupfer $ SPRITE (Berkeley)";
  534. d88 1
  535. a88 1
  536.     char *savedPtr, *end;
  537. d268 1
  538. a268 1
  539.             ptr = va_arg(args, char *);
  540. d298 3
  541. @
  542.  
  543.  
  544. 1.5.1.1
  545. log
  546. @Initial branch for Sprite server.
  547. @
  548. text
  549. @d17 1
  550. a17 1
  551. static char rcsid[] = "$Header: /sprite/src/lib/c/stdio/RCS/vfscanf.c,v 1.5 90/09/11 14:27:16 kupfer Exp Locker: rab $ SPRITE (Berkeley)";
  552. @
  553.  
  554.  
  555. 1.4
  556. log
  557. @fixed bug with encountering EOF reading a string
  558. @
  559. text
  560. @d17 1
  561. a17 1
  562. static char rcsid[] = "$Header: /sprite/src/lib/c/stdio/RCS/vfscanf.c,v 1.3 88/07/25 13:12:45 ouster Exp Locker: douglis $ SPRITE (Berkeley)";
  563. d20 1
  564. d87 1
  565. a87 1
  566.     register char *ptr;
  567. @
  568.  
  569.  
  570. 1.3
  571. log
  572. @Lint.
  573. @
  574. text
  575. @d17 1
  576. a17 1
  577. static char rcsid[] = "$Header: vfscanf.c,v 1.2 88/07/21 09:36:33 ouster Exp $ SPRITE (Berkeley)";
  578. d175 7
  579. @
  580.  
  581.  
  582. 1.2
  583. log
  584. @Change from _doscan to vfscanf.
  585. @
  586. text
  587. @d17 1
  588. a17 1
  589. static char rcsid[] = "$Header: vfscanf.c,v 1.1 88/06/10 16:23:37 ouster Exp $ SPRITE (Berkeley)";
  590. d20 4
  591. a23 4
  592. #include "stdio.h"
  593. #include "ctype.h"
  594. #include "stdlib.h"
  595. #include "varargs.h"
  596. @
  597.  
  598.  
  599. 1.1
  600. log
  601. @Initial revision
  602. @
  603. text
  604. @d2 1
  605. a2 1
  606.  * _doscan.c --
  607. d4 1
  608. a4 1
  609.  *    Source code for the "_doscan" library procedure.
  610. d17 1
  611. a17 1
  612. static char rcsid[] = "$Header: atoi.c,v 1.1 88/04/28 17:20:23 ouster Exp $ SPRITE (Berkeley)";
  613. d41 1
  614. a41 1
  615.  * _doscan --
  616. d60 2
  617. a61 1
  618. _doscan(format, args, stream)
  619. d65 1
  620. a65 1
  621.     va_list *args;        /* Addresses of a variable number of arguments
  622. a66 1
  623.     register FILE *stream;    /* Where to read characters for parsing. */
  624. d237 1
  625. a237 1
  626.             ptr = va_arg(*args, char *);
  627. d260 1
  628. a260 1
  629.             ptr = va_arg(*args, char *);
  630. d384 1
  631. a384 1
  632.             *(va_arg(*args, double *)) = d;
  633. d386 1
  634. a386 1
  635.             *(va_arg(*args, float *)) = d;
  636. d440 1
  637. a440 1
  638.             *(va_arg(*args, short *)) = i;
  639. d442 1
  640. a442 1
  641.             *(va_arg(*args, int *)) = i;
  642. @
  643.